// Purpose.  Flyweight design pattern
//
// 1. Identify shareable state (intrinsic) and non-shareable state (extrinsic)
// 2. Create a Factory that can return an existing object or a new object
// 3. The client must use the Factory instead of "new" to request objects
// 4. The client (or a third party) must compute the extrinsic state

import java.awt.*;
import java.awt.event.*;
import javax.swing.JOptionPane;
import java.lang.Character.Subset;

class LinkFace {

	LinkFace next;
	Subject sub;

	public LinkFace( Subject s ) {
		sub = s;
	}

	public void addLast( LinkFace l ) {
		if (next != null) next.addLast( l );  
		else              next = l; 
	}

	public void handle(int number) {
		
		// System.out.println("handle " + Integer.toString(number));
		sub.setState(number);		
}
}


class FlyweightFactory {
   private static java.util.Hashtable ht = new java.util.Hashtable();
   private static ButtonListener bl = new ButtonListener();
   public static Button makeButton( String num ) {
      if (ht.containsValue( num ))
         return (Button) ht.get( num );        // 2. Return an existing object
      Button btn = new Button( num );          // 1. Identify intrinsic state
      btn.addActionListener( bl );
      ht.put( num, btn );
      return btn;                              // 2. Return a new object
   }
   public static void report() {
      System.out.print( "size=" + ht.size() + "   " );
      for (java.util.Enumeration e = ht.keys(); e.hasMoreElements(); )
         System.out.print( e.nextElement() + " " );
      System.out.println();
   }  
}

class ButtonListener implements ActionListener {
	
   public void actionPerformed( ActionEvent e) {
   
      Button      btn  = (Button) e.getSource();
      java.awt.Component[] btns = btn.getParent().getComponents();
      GoodFrame parent = (GoodFrame)(btn.getParent());
      float stuff[] = new float[500];
      int i = 0;
      for ( ; i < btns.length; i++)
         if (btn == btns[i]) break;
         
      parent.chain.handle(Integer.parseInt(e.getActionCommand()));
      System.out.println(i);
   }  
}

class GoodFrame extends Frame {
   Subject sub = new Subject();
	LinkFace chain = new LinkFace(sub);
	final int port = 6666;
	RequestListener listener = new RequestListener(sub, port);
			
	public GoodFrame() {
			
		// add close event handler
		addWindowListener( new WindowAdapter() {
			public void windowClosing( WindowEvent e ) {	
            listener.dispose();											
				System.exit(0);
			}
		} );
      listener.start();
	}
}

class FlyweightDemo {
   public static final int NUM = 20;
   public static final int RAN = 15;

   public static void main( String[] args ) {
      Frame frame = new GoodFrame( );
      frame.setLayout( new GridLayout( NUM, NUM ) );
      for (int i=0; i < NUM; i++)
         for (int j=0; j < NUM; j++)
            // 3. The client must use the Factory to request objects
            frame.add( FlyweightFactory.makeButton( 
               Integer.toString( i*NUM + j ) ) );
      frame.pack();
      frame.setVisible( true );
      FlyweightFactory.report();
   }  
}

